﻿using System;
using System.Web;

/// <summary>
/// 判断网页是否被机器人频繁调用
/// 调用样例：
/// if (IsRobot.Test("Query", 1, 60, 6)){...}
/// </summary>
public class IsRobot
{
	public IsRobot()
	{
		//
		// TODO: 在此处添加构造函数逻辑
		//
	}

    public static bool Test(string CounterName, int Delay, int TimeWindow, int MaxCount)
    {
        //推荐参数：（时间单位：妙）
        //查询航班参数：Counter=Query,Delay=1,TimeWindow=60,MaxCount=6
        //订座参数：Counter=Book,Delay=20,TimeWindow=600,MaxCount=5
        //登录参数：Counter=Logon,Delay=3,TimeWindow=60,MaxCount=6

        //如果客户端不能传来会话ID，则判定为机器人！测试用会话变量在必访问页面生成。
        //由于本系统中页面无会话不能访问任何功能，所以此处Disable会话测试功能。
        //if (HttpContext.Current.Session["TESTER"] == null)
        //    return true;

        bool ret1 = false, ret2 = false;
        DateTime dt1, dtnow;
        dtnow = DateTime.Now;
        if (HttpContext.Current.Session[CounterName + "_LastAccess"] == null)
        {
            HttpContext.Current.Session[CounterName + "_LastAccess"] = dtnow.ToString();
            HttpContext.Current.Session[CounterName + "_WindowStartAt"] = dtnow.ToString();
            HttpContext.Current.Session[CounterName + "_WindowCount"] = 1;
            return false;
        }
        dt1 = Convert.ToDateTime(HttpContext.Current.Session[CounterName + "_LastAccess"]);
        TimeSpan span = dtnow - dt1;
        HttpContext.Current.Session[CounterName + "_LastAccess"] = dtnow.ToString();
        if (span.TotalSeconds < Delay)
        {
            ret1 = true; //暂不返回，后面还需追加此次访问次数
        }


        if (HttpContext.Current.Session[CounterName + "_WindowStartAt"] == null)
        {
            HttpContext.Current.Session[CounterName + "_WindowStartAt"] = dtnow.ToString();
            HttpContext.Current.Session[CounterName + "_WindowCount"] = 0;
        }
        dt1 = Convert.ToDateTime(HttpContext.Current.Session[CounterName + "_WindowStartAt"]);
        span = dtnow - dt1;
        if (span.TotalSeconds > TimeWindow)
        {
            HttpContext.Current.Session[CounterName + "_WindowStartAt"] = dtnow.ToString();
            if (Convert.ToInt16(HttpContext.Current.Session[CounterName + "_WindowCount"]) > MaxCount * 2)
            {
                //如果上一时间窗口访问次数（含访问被限制而失败的次数）远大于最大值，很可能为机器人或恶意点击，在新的时间窗口给予减少访问次数的惩罚！
                HttpContext.Current.Session[CounterName + "_WindowCount"] = MaxCount / 2;// Convert.ToInt16(HttpContext.Current.Session[Counter + "_WindowCount"]) - MaxCount;

                ////如果上一时间窗口访问次数（含访问被限制而失败的次数）远大于最大值，很可能为机器人或恶意点击，在会话期内拒绝访问！
                //HttpContext.Current.Session[CounterName + "_WindowCount"] = MaxCount * 3;
            }
            else
            {
                HttpContext.Current.Session[CounterName + "_WindowCount"] = 0;
            }
        }
        
        if (HttpContext.Current.Session[CounterName + "_WindowCount"] == null)
            HttpContext.Current.Session[CounterName + "_WindowCount"] = 0;
        int last_count = Convert.ToInt16(HttpContext.Current.Session[CounterName + "_WindowCount"]);
        if (last_count > MaxCount)
            ret2 = true;
        HttpContext.Current.Session[CounterName + "_WindowCount"] = Convert.ToInt16(HttpContext.Current.Session[CounterName + "_WindowCount"]) + 1;

        return ret1 || ret2;
    }
}
